package assembler;

import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.Hashtable;
import java.util.Vector;

class Instructions
{

    Instructions()
    {
    }

    public static void parse(Vector vector, ParsedLine parsedline)
    {
        try
        {
            String s = (String)vector.elementAt(1);
            if(s.equals("ADD") || s.equals("SUB") || s.equals("AND") || s.equals("OR"))
            {
                ADD_Parse(vector, parsedline);
            } else
            if(s.equals("NOT") || s.equals("SHL") || s.equals("SHR"))
            {
                NOT_Parse(vector, parsedline);
            } else
            if(s.equals("BPOS"))
            {
                BPOS_Parse(vector, parsedline);
            } else
            if(s.equals("BODD") || s.equals("BZERO") || s.equals("BNEG"))
            {
                BODD_Parse(vector, parsedline);
            } else
            if(s.equals("BNZERO") || s.equals("BEVEN"))
            {
                BNZERO_Parse(vector, parsedline);
            } else
            if(s.equals("BGEQ") || s.equals("BLEQ") || s.equals("BGT") || s.equals("BLT") || s.equals("BEQ") || s.equals("BNEQ"))
            {
                BGEQ_Parse(vector, parsedline);
            } else
            if(s.equals("JUMP"))
            {
                JUMP_Parse(vector, parsedline);
            } else
            if(s.equals("CALL"))
            {
                CALL_Parse(vector, parsedline);
            } else
            if(s.equals("RET"))
            {
                RET_Parse(vector, parsedline);
            } else
            if(s.equals("PUSH") || s.equals("POP"))
            {
                PUSH_Parse(vector, parsedline);
            } else
            if(s.equals("NOP") || s.equals("HALT"))
            {
                NOP_Parse(vector, parsedline);
            } else
            if(s.equals("LOAD") || s.equals("STORE"))
            {
                LOAD_Parse(vector, parsedline);
            } else
            if(!s.equals(""))
            {
                printError(parsedline, "Unknown instruction.");
            }
        }
        catch(ArrayIndexOutOfBoundsException arrayindexoutofboundsexception)
        {
            printError(parsedline, "Unknown error parsing instruction.");
        }
    }

    public static int generate(ParsedLine parsedline, PrintWriter printwriter, Hashtable hashtable, int i)
    {
        try
        {
            String s = parsedline.getInst();
            if(s.equals("ADD"))
            {
                i += 4 * ADD_Generate(parsedline, "0011", printwriter);
            } else
            if(s.equals("SUB"))
            {
                i += 4 * ADD_Generate(parsedline, "1111", printwriter);
            } else
            if(s.equals("AND"))
            {
                i += 4 * ADD_Generate(parsedline, "0010", printwriter);
            } else
            if(s.equals("OR"))
            {
                i += 4 * ADD_Generate(parsedline, "0001", printwriter);
            } else
            if(s.equals("NOT"))
            {
                i += 4 * NOT_Generate(parsedline, "0100", printwriter);
            } else
            if(s.equals("SHL"))
            {
                i += 4 * NOT_Generate(parsedline, "0010", printwriter);
            } else
            if(s.equals("SHR"))
            {
                i += 4 * NOT_Generate(parsedline, "0001", printwriter);
            } else
            if(s.equals("BODD"))
            {
                i += 4 * BODD_Generate(parsedline, "0011", printwriter, hashtable, i);
            } else
            if(s.equals("BZERO"))
            {
                i += 4 * BODD_Generate(parsedline, "0001", printwriter, hashtable, i);
            } else
            if(s.equals("BNEG"))
            {
                i += 4 * BODD_Generate(parsedline, "0010", printwriter, hashtable, i);
            } else
            if(s.equals("BPOS"))
            {
                i += 4 * BPOS_Generate(parsedline, printwriter, hashtable, i);
            } else
            if(s.equals("BNZERO"))
            {
                i += 4 * BNZERO_Generate(parsedline, printwriter, hashtable, i);
            } else
            if(s.equals("BEVEN"))
            {
                i += 4 * BEVEN_Generate(parsedline, printwriter, hashtable, i);
            } else
            if(s.equals("BGEQ") || s.equals("BLEQ"))
            {
                i += 4 * BGEQ_Generate(parsedline, printwriter, hashtable, i);
            } else
            if(s.equals("BGT") || s.equals("BLT"))
            {
                i += 4 * BGT_Generate(parsedline, printwriter, hashtable, i);
            } else
            if(s.equals("BEQ"))
            {
                i += 4 * BEQ_Generate(parsedline, printwriter, hashtable, i);
            } else
            if(s.equals("BNEQ"))
            {
                i += 4 * BNEQ_Generate(parsedline, printwriter, hashtable, i);
            } else
            if(s.equals("JUMP"))
            {
                i += 4 * JUMP_Generate(parsedline, printwriter, hashtable);
            } else
            if(s.equals("CALL"))
            {
                i += 4 * CALL_Generate(parsedline, printwriter, hashtable);
            } else
            if(s.equals("RET"))
            {
                i += 4 * RET_Generate(parsedline, printwriter);
            } else
            if(s.equals("NOP"))
            {
                i += 4 * NOP_Generate(parsedline, printwriter);
            } else
            if(s.equals("HALT"))
            {
                i += 4 * HALT_Generate(parsedline, printwriter);
            } else
            if(s.equals("PUSH"))
            {
                i += 4 * PUSH_Generate(parsedline, printwriter);
            } else
            if(s.equals("POP"))
            {
                i += 4 * POP_Generate(parsedline, printwriter);
            } else
            if(s.equals("LOAD"))
            {
                i += 4 * LOAD_Generate(parsedline, printwriter, "0001", hashtable);
            } else
            if(s.equals("STORE"))
            {
                i += 4 * LOAD_Generate(parsedline, printwriter, "0010", hashtable);
            } else
            {
                printError(parsedline, "Unknown instruction: " + parsedline.getInst() + ".");
            }
        }
        catch(ArrayIndexOutOfBoundsException arrayindexoutofboundsexception)
        {
            printError(parsedline, "Crap! - This shouldn't happen.");
        }
        return i;
    }

    private static int ADD_Generate(ParsedLine parsedline, String s, PrintWriter printwriter)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ":");
        }
        printwriter.println(parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1) + " " + parsedline.getOperand(2));
        int i = parsedline.getAddrMode();
        if(i == 1)
        {
            String s1 = parsedline.getOperand(2);
            long l = ParsedLine.getNumValue(s1.substring(1, s1.length()));
            if(l > (long)MAX_OFFSET || l < (long)MIN_OFFSET)
            {
                String s2 = imm2Bin32(s1);
                printwriter.println("** LOADi R15 " + s2.substring(16, s2.length()));
                printwriter.println("1001001100001111" + s2.substring(16, s2.length()));
                printwriter.println("** LOADUi R15 " + s2.substring(0, 16));
                printwriter.println("1001100100001111" + s2.substring(0, 16));
                printwriter.println("** " + parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1) + " R15");
                printwriter.println("0010" + s + reg2Bin(parsedline.getOperand(1)) + "1111" + reg2Bin(parsedline.getOperand(0)) + Assembler.binString(0, 12));
                return 3;
            } else
            {
                printwriter.println("** " + parsedline.getInst() + "i " + parsedline.getOperand(0) + " " + parsedline.getOperand(1) + " " + parsedline.getOperand(2));
                printwriter.println("1011" + s + reg2Bin(parsedline.getOperand(1)) + reg2Bin(parsedline.getOperand(0)) + imm2Bin16(parsedline.getOperand(2)));
                return 1;
            }
        }
        if(i == 3)
        {
            printwriter.println("** " + parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1) + " " + parsedline.getOperand(2));
            printwriter.println("0010" + s + reg2Bin(parsedline.getOperand(1)) + reg2Bin(parsedline.getOperand(2)) + reg2Bin(parsedline.getOperand(0)) + Assembler.binString(0, 12));
            return 1;
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
            return 0;
        }
    }

    private static int NOT_Generate(ParsedLine parsedline, String s, PrintWriter printwriter)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.println(parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1));
        int i = parsedline.getAddrMode();
        if(i == 3)
        {
            printwriter.println("** " + parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1));
            printwriter.println("0110" + s + "0000" + reg2Bin(parsedline.getOperand(1)) + reg2Bin(parsedline.getOperand(0)) + Assembler.binString(0, 12));
            return 1;
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
            return 0;
        }
    }

    private static int BODD_Generate(ParsedLine parsedline, String s, PrintWriter printwriter, Hashtable hashtable, int i)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.println(parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1));
        int j = parsedline.getAddrMode();
        if(j == 3)
        {
            Integer integer = (Integer)hashtable.get(((Object) (parsedline.getOperand(1))));
            if(integer == null)
            {
                printError(parsedline, "Undefined label " + parsedline.getOperand(1) + ".");
            } else
            {
                int k = integer.intValue() - i;
                if(k % 4 != 0)
                {
                    printError(parsedline, "Invalid branch label " + parsedline.getOperand(1));
                } else
                if(k / 4 > MAX_OFFSET || k / 4 < MIN_OFFSET)
                {
                    printError(parsedline, "Branch target too far away,  must be within 2^16 ML instructions.");
                } else
                {
                    k /= 4;
                    printwriter.println("** " + parsedline.getInst() + " " + parsedline.getOperand(0) + " " + k);
                    printwriter.println("1110" + s + "0000" + reg2Bin(parsedline.getOperand(0)) + Assembler.binString(k, 16));
                    return 1;
                }
            }
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
        }
        return 0;
    }

    private static int BPOS_Generate(ParsedLine parsedline, PrintWriter printwriter, Hashtable hashtable, int i)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.println(parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1));
        int j = parsedline.getAddrMode();
        if(j == 3)
        {
            Integer integer = (Integer)hashtable.get(((Object) (parsedline.getOperand(1))));
            if(integer == null)
            {
                printError(parsedline, "Undefined label " + parsedline.getOperand(1) + ".");
            } else
            {
                int k = integer.intValue() - (i + 8);
                if(k % 4 != 0)
                {
                    printError(parsedline, "Invalid branch label " + parsedline.getOperand(1));
                } else
                if(k / 4 > MAX_OFFSET || k / 4 < MIN_OFFSET)
                {
                    printError(parsedline, "Branch target too far away,  must be within 2^16 ML instructions.");
                } else
                {
                    k /= 4;
                    printwriter.println("** BNEG " + parsedline.getOperand(0) + " 3");
                    printwriter.println("111000100000" + reg2Bin(parsedline.getOperand(0)) + Assembler.binString(3, 16));
                    printwriter.println("** BZERO " + parsedline.getOperand(0) + " 2");
                    printwriter.println("111000010000" + reg2Bin(parsedline.getOperand(0)) + Assembler.binString(2, 16));
                    printwriter.println("** BRANCH " + k);
                    printwriter.println("1100000100000000" + Assembler.binString(k, 16));
                    return 3;
                }
            }
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
        }
        return 0;
    }

    private static int BNZERO_Generate(ParsedLine parsedline, PrintWriter printwriter, Hashtable hashtable, int i)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.println(parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1));
        int j = parsedline.getAddrMode();
        if(j == 3)
        {
            Integer integer = (Integer)hashtable.get(((Object) (parsedline.getOperand(1))));
            if(integer == null)
            {
                printError(parsedline, "Undefined label " + parsedline.getOperand(1) + ".");
            } else
            {
                int k = integer.intValue() - (i + 4);
                if(k % 4 != 0)
                {
                    printError(parsedline, "Invalid branch label " + parsedline.getOperand(1));
                } else
                if(k / 4 > MAX_OFFSET || k / 4 < MIN_OFFSET)
                {
                    printError(parsedline, "Branch target too far away,  must be within 2^16 ML instructions.");
                } else
                {
                    k /= 4;
                    printwriter.println("** BZERO " + parsedline.getOperand(0) + " 2");
                    printwriter.println("111000010000" + reg2Bin(parsedline.getOperand(0)) + Assembler.binString(2, 16));
                    printwriter.println("** BRANCH " + k);
                    printwriter.println("1100000100000000" + Assembler.binString(k, 16));
                    return 2;
                }
            }
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
        }
        return 0;
    }

    private static int BEVEN_Generate(ParsedLine parsedline, PrintWriter printwriter, Hashtable hashtable, int i)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.println(parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1));
        int j = parsedline.getAddrMode();
        if(j == 3)
        {
            Integer integer = (Integer)hashtable.get(((Object) (parsedline.getOperand(1))));
            if(integer == null)
            {
                printError(parsedline, "Undefined label " + parsedline.getOperand(1) + ".");
            } else
            {
                int k = integer.intValue() - (i + 4);
                if(k % 4 != 0)
                {
                    printError(parsedline, "Invalid branch label " + parsedline.getOperand(1));
                } else
                if(k / 4 > MAX_OFFSET || k / 4 < MIN_OFFSET)
                {
                    printError(parsedline, "Branch target too far away,  must be within 2^16 ML instructions.");
                } else
                {
                    k /= 4;
                    printwriter.println("** BODD " + parsedline.getOperand(0) + " 2");
                    printwriter.println("111000110000" + reg2Bin(parsedline.getOperand(0)) + Assembler.binString(2, 16));
                    printwriter.println("** BRANCH " + k);
                    printwriter.println("1100000100000000" + Assembler.binString(k, 16));
                    return 2;
                }
            }
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
        }
        return 0;
    }

    private static int BGEQ_Generate(ParsedLine parsedline, PrintWriter printwriter, Hashtable hashtable, int i)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.println(parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1) + " " + parsedline.getOperand(2));
        int j = parsedline.getAddrMode();
        if(j == 3)
        {
            Integer integer = (Integer)hashtable.get(((Object) (parsedline.getOperand(2))));
            if(integer == null)
            {
                printError(parsedline, "Undefined label " + parsedline.getOperand(2) + ".");
            } else
            {
                int k = integer.intValue() - (i + 4);
                int l = integer.intValue() - (i + 8);
                if(k % 4 != 0)
                {
                    printError(parsedline, "Invalid branch label " + parsedline.getOperand(2));
                } else
                if(k / 4 > MAX_OFFSET || k / 4 < MIN_OFFSET || l / 4 > MAX_OFFSET || l / 4 < MIN_OFFSET)
                {
                    printError(parsedline, "Branch target too far away,  must be within 2^16 ML instructions.");
                } else
                {
                    k /= 4;
                    l /= 4;
                    if(parsedline.getInst().equals("BGEQ"))
                    {
                        printwriter.println("** SUB R15 " + parsedline.getOperand(1) + " " + parsedline.getOperand(0));
                        printwriter.println("00101111" + reg2Bin(parsedline.getOperand(1)) + reg2Bin(parsedline.getOperand(0)) + "1111" + Assembler.binString(0, 12));
                    } else
                    {
                        printwriter.println("** SUB R15 " + parsedline.getOperand(0) + " " + parsedline.getOperand(1));
                        printwriter.println("00101111" + reg2Bin(parsedline.getOperand(0)) + reg2Bin(parsedline.getOperand(1)) + "1111" + Assembler.binString(0, 12));
                    }
                    printwriter.println("** BNEG R15 " + k);
                    printwriter.println("1110001000001111" + Assembler.binString(k, 16));
                    printwriter.println("** BZERO R15 " + l);
                    printwriter.println("1110000100001111" + Assembler.binString(l, 16));
                    return 3;
                }
            }
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
        }
        return 0;
    }

    private static int BGT_Generate(ParsedLine parsedline, PrintWriter printwriter, Hashtable hashtable, int i)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.println(parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1) + " " + parsedline.getOperand(2));
        int j = parsedline.getAddrMode();
        if(j == 3)
        {
            Integer integer = (Integer)hashtable.get(((Object) (parsedline.getOperand(2))));
            if(integer == null)
            {
                printError(parsedline, "Undefined label " + parsedline.getOperand(2) + ".");
            } else
            {
                int k = integer.intValue() - (i + 4);
                if(k % 4 != 0)
                {
                    printError(parsedline, "Invalid branch label " + parsedline.getOperand(1));
                } else
                if(k / 4 > MAX_OFFSET || k / 4 < MIN_OFFSET)
                {
                    printError(parsedline, "Branch target too far away,  must be within 2^16 ML instructions.");
                } else
                {
                    k /= 4;
                    if(parsedline.getInst().equals("BGT"))
                    {
                        printwriter.println("** SUB R15 " + parsedline.getOperand(1) + " " + parsedline.getOperand(0));
                        printwriter.println("00101111" + reg2Bin(parsedline.getOperand(1)) + reg2Bin(parsedline.getOperand(0)) + "1111" + Assembler.binString(0, 12));
                    } else
                    {
                        printwriter.println("** SUB R15 " + parsedline.getOperand(0) + " " + parsedline.getOperand(1));
                        printwriter.println("00101111" + reg2Bin(parsedline.getOperand(0)) + reg2Bin(parsedline.getOperand(1)) + "1111" + Assembler.binString(0, 12));
                    }
                    printwriter.println("** BNEG R15 " + k);
                    printwriter.println("1110001000001111" + Assembler.binString(k, 16));
                    return 2;
                }
            }
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
        }
        return 0;
    }

    private static int BEQ_Generate(ParsedLine parsedline, PrintWriter printwriter, Hashtable hashtable, int i)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.println(parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1) + " " + parsedline.getOperand(2));
        int j = parsedline.getAddrMode();
        if(j == 3)
        {
            Integer integer = (Integer)hashtable.get(((Object) (parsedline.getOperand(2))));
            if(integer == null)
            {
                printError(parsedline, "Undefined label " + parsedline.getOperand(2) + ".");
            } else
            {
                int k = integer.intValue() - (i + 4);
                if(k % 4 != 0)
                {
                    printError(parsedline, "Invalid branch label " + parsedline.getOperand(1));
                } else
                if(k / 4 > MAX_OFFSET || k / 4 < MIN_OFFSET)
                {
                    printError(parsedline, "Branch target too far away,  must be within 2^16 ML instructions.");
                } else
                {
                    k /= 4;
                    if(parsedline.getInst().equals("BGT"))
                    {
                        printwriter.println("** SUB R15 " + parsedline.getOperand(1) + " " + parsedline.getOperand(0));
                        printwriter.println("00101111" + reg2Bin(parsedline.getOperand(1)) + reg2Bin(parsedline.getOperand(0)) + "1111" + Assembler.binString(0, 12));
                    } else
                    {
                        printwriter.println("** SUB R15 " + parsedline.getOperand(0) + " " + parsedline.getOperand(1));
                        printwriter.println("00101111" + reg2Bin(parsedline.getOperand(0)) + reg2Bin(parsedline.getOperand(1)) + "1111" + Assembler.binString(0, 12));
                    }
                    printwriter.println("** BZERO R15 " + k);
                    printwriter.println("1110000100001111" + Assembler.binString(k, 16));
                    return 2;
                }
            }
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
        }
        return 0;
    }

    private static int BNEQ_Generate(ParsedLine parsedline, PrintWriter printwriter, Hashtable hashtable, int i)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.println(parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1) + " " + parsedline.getOperand(2));
        int j = parsedline.getAddrMode();
        if(j == 3)
        {
            Integer integer = (Integer)hashtable.get(((Object) (parsedline.getOperand(2))));
            if(integer == null)
            {
                printError(parsedline, "Undefined label " + parsedline.getOperand(2) + ".");
            } else
            {
                int k = integer.intValue() - (i + 8);
                if(k % 4 != 0)
                {
                    printError(parsedline, "Invalid branch label " + parsedline.getOperand(2));
                } else
                if(k / 4 > MAX_OFFSET || k / 4 < MIN_OFFSET)
                {
                    printError(parsedline, "Branch target too far away,  must be within 2^16 ML instructions.");
                } else
                {
                    k /= 4;
                    if(parsedline.getInst().equals("BGEQ"))
                    {
                        printwriter.println("** SUB R15 " + parsedline.getOperand(1) + " " + parsedline.getOperand(0));
                        printwriter.println("00101111" + reg2Bin(parsedline.getOperand(1)) + reg2Bin(parsedline.getOperand(0)) + "1111" + Assembler.binString(0, 12));
                    } else
                    {
                        printwriter.println("** SUB R15 " + parsedline.getOperand(0) + " " + parsedline.getOperand(1));
                        printwriter.println("00101111" + reg2Bin(parsedline.getOperand(0)) + reg2Bin(parsedline.getOperand(1)) + "1111" + Assembler.binString(0, 12));
                    }
                    printwriter.println("** BZERO R15 2");
                    printwriter.println("1110000100001111" + Assembler.binString(2, 16));
                    printwriter.println("** BRANCH R15 " + k);
                    printwriter.println("1100000100001111" + Assembler.binString(k, 16));
                    return 3;
                }
            }
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
        }
        return 0;
    }

    private static int JUMP_Generate(ParsedLine parsedline, PrintWriter printwriter, Hashtable hashtable)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.println(parsedline.getInst() + " " + parsedline.getOperand(0));
        int i = parsedline.getAddrMode();
        if(i == 3)
        {
            Integer integer = (Integer)hashtable.get(((Object) (parsedline.getOperand(0))));
            if(integer == null)
            {
                printError(parsedline, "Undefined label " + parsedline.getOperand(0) + ".");
            } else
            {
                int j = integer.intValue();
                if(j % 4 != 0)
                {
                    printError(parsedline, "Invalid jump label " + parsedline.getOperand(0));
                }
                String s = Assembler.binString(j, 32);
                printwriter.println("** LOADi R15 " + s.substring(16, s.length()));
                printwriter.println("1001001100001111" + s.substring(16, s.length()));
                printwriter.println("** LOADUi R15 " + s.substring(0, 16));
                printwriter.println("1001100100001111" + s.substring(0, 16));
                printwriter.println("** JREG R15");
                printwriter.println("1110010000001111" + Assembler.binString(0, 16));
                return 3;
            }
        } else
        {
            if(i == 4)
            {
                printwriter.println("** JREG " + parsedline.getOperand(0));
                printwriter.println("111001000000" + reg2Bin(parsedline.getOperand(0)) + Assembler.binString(0, 16));
                return 1;
            }
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
        }
        return 0;
    }

    private static int CALL_Generate(ParsedLine parsedline, PrintWriter printwriter, Hashtable hashtable)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ":");
        }
        printwriter.println(parsedline.getInst() + " " + parsedline.getOperand(0));
        int i = parsedline.getAddrMode();
        if(i == 3)
        {
            Integer integer = (Integer)hashtable.get(((Object) (parsedline.getOperand(0))));
            if(integer == null)
            {
                printError(parsedline, "Undefined label " + parsedline.getOperand(0) + ".");
            } else
            {
                int j = integer.intValue();
                if(j % 4 != 0)
                {
                    printError(parsedline, "Invalid call label " + parsedline.getOperand(0));
                }
                String s = Assembler.binString(j, 32);
                printwriter.println("** LOADi R15 " + s.substring(16, s.length()));
                printwriter.println("1001001100001111" + s.substring(16, s.length()));
                printwriter.println("** LOADUi R15 " + s.substring(0, 16));
                printwriter.println("1001100100001111" + s.substring(0, 16));
                printwriter.println("** JAL R15 R12");
                printwriter.println("1011010011111100" + Assembler.binString(0, 16));
                return 3;
            }
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
        }
        return 0;
    }

    private static int RET_Generate(ParsedLine parsedline, PrintWriter printwriter)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.println(parsedline.getInst());
        int i = parsedline.getAddrMode();
        if(i == 1)
        {
            printwriter.println("** JREG R12");
            printwriter.println("1110010000001100" + Assembler.binString(0, 16));
            return 1;
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
            return 0;
        }
    }

    private static int NOP_Generate(ParsedLine parsedline, PrintWriter printwriter)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.println(parsedline.getInst());
        int i = parsedline.getAddrMode();
        if(i == 1)
        {
            printwriter.println("** NOP");
            printwriter.println(Assembler.binString(0, 32));
            return 1;
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
            return 0;
        }
    }

    private static int HALT_Generate(ParsedLine parsedline, PrintWriter printwriter)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.println(parsedline.getInst());
        int i = parsedline.getAddrMode();
        if(i == 1)
        {
            printwriter.println("** HALT");
            printwriter.println(Assembler.binString(-1, 32));
            return 1;
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
            return 0;
        }
    }

    private static int PUSH_Generate(ParsedLine parsedline, PrintWriter printwriter)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.println(parsedline.getInst() + " " + parsedline.getOperand(0));
        int i = parsedline.getAddrMode();
        if(i == 3)
        {
            printwriter.println("** STORE R13 " + parsedline.getOperand(0));
            printwriter.println("010000101101" + reg2Bin(parsedline.getOperand(0)) + Assembler.binString(0, 16));
            printwriter.println("** SUBi R13 R13 4");
            printwriter.println("1011111111011101" + Assembler.binString(4, 16));
            return 2;
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
            return 0;
        }
    }

    private static int POP_Generate(ParsedLine parsedline, PrintWriter printwriter)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.println(parsedline.getInst() + " " + parsedline.getOperand(0));
        int i = parsedline.getAddrMode();
        if(i == 3)
        {
            printwriter.println("** ADDi R13 R13 4");
            printwriter.println("1011001111011101" + Assembler.binString(4, 16));
            printwriter.println("** LOAD " + parsedline.getOperand(0) + " R13");
            printwriter.println("010000011101" + reg2Bin(parsedline.getOperand(0)) + Assembler.binString(0, 16));
            return 2;
        } else
        {
            printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
            return 0;
        }
    }

    private static int LOAD_Generate(ParsedLine parsedline, PrintWriter printwriter, String s, Hashtable hashtable)
    {
        printwriter.print("* ");
        if(parsedline.getLabel() != null)
        {
            printwriter.print(parsedline.getLabel() + ": ");
        }
        printwriter.print(parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1));
        int i = parsedline.getAddrMode();
        if(i == 1)
        {
            printwriter.println();
            String s1 = parsedline.getOperand(1);
            long l = ParsedLine.getNumValue(s1.substring(1, s1.length()));
            if(l > (long)MAX_OFFSET || l < (long)MIN_OFFSET)
            {
                String s4 = Assembler.binString((int)l, 32);
                printwriter.println("** LOADi " + parsedline.getOperand(0) + " " + s4.substring(16, s4.length()));
                printwriter.println("100100110000" + reg2Bin(parsedline.getOperand(0)) + s4.substring(16, s4.length()));
                printwriter.println("** LOADUi " + parsedline.getOperand(0) + " " + s4.substring(0, 16));
                printwriter.println("100110010000" + reg2Bin(parsedline.getOperand(0)) + s4.substring(0, 16));
                return 2;
            } else
            {
                String s5 = Assembler.binString((int)l, 16);
                printwriter.println("** LOADi " + parsedline.getOperand(0) + " " + Assembler.binString((int)l, 16));
                printwriter.println("100100110000" + reg2Bin(parsedline.getOperand(0)) + Assembler.binString((int)l, 16));
                return 1;
            }
        }
        if(i == 2)
        {
            String s2 = parsedline.getOperand(1);
            Integer integer1 = (Integer)hashtable.get(((Object) (s2.substring(1, s2.length()))));
            if(integer1 == null)
            {
                printError(parsedline, "Undefined label " + s2 + ".");
            } else
            {
                int k = integer1.intValue();
                printwriter.println();
                String s6 = Assembler.binString(k, 32);
                printwriter.println("** LOADi " + parsedline.getOperand(0) + " " + s6.substring(16, s6.length()));
                printwriter.println("100100110000" + reg2Bin(parsedline.getOperand(0)) + s6.substring(16, s6.length()));
                printwriter.println("** LOADUi " + parsedline.getOperand(0) + " " + s6.substring(0, 16));
                printwriter.println("100110010000" + reg2Bin(parsedline.getOperand(0)) + s6.substring(0, 16));
                return 2;
            }
        } else
        {
            if(i == 4)
            {
                printwriter.println();
                printwriter.println("** " + parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1));
                printwriter.println("0100" + s + reg2Bin(parsedline.getOperand(1)) + reg2Bin(parsedline.getOperand(0)) + Assembler.binString(0, 16));
                return 1;
            }
            if(i == 5)
            {
                printwriter.println(" " + parsedline.getOperand(2));
                printwriter.println("** " + parsedline.getInst() + " " + parsedline.getOperand(0) + " " + parsedline.getOperand(1) + " " + parsedline.getOperand(2));
                printwriter.println("0100" + s + reg2Bin(parsedline.getOperand(1)) + reg2Bin(parsedline.getOperand(0)) + imm2Bin16(parsedline.getOperand(2)));
                return 1;
            }
            if(i == 3)
            {
                printwriter.println();
                Integer integer = (Integer)hashtable.get(((Object) (parsedline.getOperand(1))));
                if(integer == null)
                {
                    printError(parsedline, "Undefined label " + parsedline.getOperand(1) + ".");
                } else
                {
                    int j = integer.intValue();
                    if(j % 4 != 0)
                    {
                        printError(parsedline, "Invalid load label " + parsedline.getOperand(1));
                    }
                    String s3 = Assembler.binString(j, 32);
                    printwriter.println("** LOADi R15 " + s3.substring(16, s3.length()));
                    printwriter.println("1001001100001111" + s3.substring(16, s3.length()));
                    printwriter.println("** LOADUi R15 " + s3.substring(0, 16));
                    printwriter.println("1001100100001111" + s3.substring(0, 16));
                    printwriter.println("** " + parsedline.getInst() + " " + parsedline.getOperand(0) + " R15 " + Assembler.binString(0, 16));
                    printwriter.println("0100" + s + "1111" + reg2Bin(parsedline.getOperand(0)) + Assembler.binString(0, 16));
                    return 3;
                }
            } else
            {
                printError(parsedline, "Invalid addressing mode for " + parsedline.getInst() + ".");
            }
        }
        return 0;
    }

    private static void ADD_Parse(Vector vector, ParsedLine parsedline)
    {
        parsedline.setInst((String)vector.elementAt(1));
        if(vector.size() != 5)
        {
            printError(parsedline, "3 operands required.");
        }
        try
        {
            String s = (String)vector.elementAt(2);
            String s1 = (String)vector.elementAt(3);
            String s2 = (String)vector.elementAt(4);
            if(!validRegister(s) || !validRegister(s1))
            {
                printError(parsedline, "First two operands must be registers [R0-R15].");
            } else
            {
                parsedline.setOperand(0, s);
                parsedline.setOperand(1, s1);
            }
            if(validRegister(s2))
            {
                parsedline.setAddrMode(3);
                parsedline.setOperand(2, s2);
                parsedline.setExpFactor(1);
            } else
            if(validImmediate(s2))
            {
                parsedline.setAddrMode(1);
                parsedline.setOperand(2, s2);
                if(ParsedLine.getNumValue(s2.substring(1, s2.length())) > (long)MAX_OFFSET || ParsedLine.getNumValue(s2.substring(1, s2.length())) < (long)MIN_OFFSET)
                {
                    parsedline.setExpFactor(3);
                } else
                {
                    parsedline.setExpFactor(1);
                }
            } else
            {
                printError(parsedline, "Bad third operand.");
            }
        }
        catch(ArrayIndexOutOfBoundsException arrayindexoutofboundsexception) { }
    }

    private static void NOT_Parse(Vector vector, ParsedLine parsedline)
    {
        parsedline.setInst((String)vector.elementAt(1));
        if(vector.size() != 4)
        {
            printError(parsedline, "2 operands required.");
        }
        try
        {
            String s = (String)vector.elementAt(2);
            String s1 = (String)vector.elementAt(3);
            if(!validRegister(s) || !validRegister(s1))
            {
                printError(parsedline, "Operands must be registers [R0-R15].");
            } else
            {
                parsedline.setAddrMode(3);
                parsedline.setOperand(0, s);
                parsedline.setOperand(1, s1);
                parsedline.setExpFactor(1);
            }
        }
        catch(ArrayIndexOutOfBoundsException arrayindexoutofboundsexception) { }
    }

    private static void BPOS_Parse(Vector vector, ParsedLine parsedline)
    {
        String s = (String)vector.elementAt(1);
        parsedline.setInst(s);
        if(vector.size() != 4)
        {
            printError(parsedline, "2 operands required.");
        }
        try
        {
            String s1 = (String)vector.elementAt(2);
            String s2 = (String)vector.elementAt(3);
            if(validRegLabel(parsedline, s1, s2))
            {
                parsedline.setAddrMode(3);
                parsedline.setOperand(0, s1);
                parsedline.setOperand(1, s2);
                parsedline.setExpFactor(3);
            }
        }
        catch(ArrayIndexOutOfBoundsException arrayindexoutofboundsexception) { }
    }

    private static void BODD_Parse(Vector vector, ParsedLine parsedline)
    {
        String s = (String)vector.elementAt(1);
        parsedline.setInst(s);
        if(vector.size() != 4)
        {
            printError(parsedline, "2 operands required.");
        }
        try
        {
            String s1 = (String)vector.elementAt(2);
            String s2 = (String)vector.elementAt(3);
            if(validRegLabel(parsedline, s1, s2))
            {
                parsedline.setAddrMode(3);
                parsedline.setOperand(0, s1);
                parsedline.setOperand(1, s2);
                parsedline.setExpFactor(1);
            }
        }
        catch(ArrayIndexOutOfBoundsException arrayindexoutofboundsexception) { }
    }

    private static void BNZERO_Parse(Vector vector, ParsedLine parsedline)
    {
        String s = (String)vector.elementAt(1);
        parsedline.setInst(s);
        if(vector.size() != 4)
        {
            printError(parsedline, "2 operands required.");
        }
        try
        {
            String s1 = (String)vector.elementAt(2);
            String s2 = (String)vector.elementAt(3);
            if(validRegLabel(parsedline, s1, s2))
            {
                parsedline.setAddrMode(3);
                parsedline.setOperand(0, s1);
                parsedline.setOperand(1, s2);
                parsedline.setExpFactor(2);
            }
        }
        catch(ArrayIndexOutOfBoundsException arrayindexoutofboundsexception) { }
    }

    private static void BGEQ_Parse(Vector vector, ParsedLine parsedline)
    {
        parsedline.setInst((String)vector.elementAt(1));
        if(vector.size() != 5)
        {
            printError(parsedline, "3 operands required.");
        }
        try
        {
            String s = (String)vector.elementAt(2);
            String s1 = (String)vector.elementAt(3);
            String s2 = (String)vector.elementAt(4);
            if(!validRegister(s) || !validRegister(s1))
            {
                printError(parsedline, "First two operands must be registers [R0-R15].");
            } else
            if(!validLabel(s2))
            {
                printError(parsedline, "Third operand must be a label.");
            } else
            {
                parsedline.setAddrMode(3);
                parsedline.setOperand(0, s);
                parsedline.setOperand(1, s1);
                parsedline.setOperand(2, s2);
                if(parsedline.getInst().equals("BNEQ") || parsedline.getInst().equals("BGEQ") || parsedline.getInst().equals("BLEQ"))
                {
                    parsedline.setExpFactor(3);
                } else
                {
                    parsedline.setExpFactor(2);
                }
            }
        }
        catch(ArrayIndexOutOfBoundsException arrayindexoutofboundsexception) { }
    }

    private static void JUMP_Parse(Vector vector, ParsedLine parsedline)
    {
        parsedline.setInst((String)vector.elementAt(1));
        if(vector.size() != 3)
        {
            printError(parsedline, "1 operand required.");
        }
        try
        {
            String s = (String)vector.elementAt(2);
            if(validRegister(s))
            {
                parsedline.setAddrMode(4);
                parsedline.setOperand(0, s);
                parsedline.setExpFactor(1);
            } else
            if(validLabel(s))
            {
                parsedline.setAddrMode(3);
                parsedline.setOperand(0, s);
                parsedline.setExpFactor(3);
            } else
            {
                printError(parsedline, "Operand must be aregister [R0-R15] or a label.");
            }
        }
        catch(ArrayIndexOutOfBoundsException arrayindexoutofboundsexception) { }
    }

    private static void CALL_Parse(Vector vector, ParsedLine parsedline)
    {
        parsedline.setInst((String)vector.elementAt(1));
        if(vector.size() != 3)
        {
            printError(parsedline, "1 operand required.");
        }
        try
        {
            String s = (String)vector.elementAt(2);
            if(validLabel(s))
            {
                parsedline.setAddrMode(3);
                parsedline.setOperand(0, s);
                parsedline.setExpFactor(3);
            } else
            {
                printError(parsedline, "Operand must be a label.");
            }
        }
        catch(ArrayIndexOutOfBoundsException arrayindexoutofboundsexception) { }
    }

    private static void RET_Parse(Vector vector, ParsedLine parsedline)
    {
        parsedline.setInst((String)vector.elementAt(1));
        if(vector.size() != 2)
        {
            printError(parsedline, "No operands permitted.");
        }
        parsedline.setAddrMode(1);
        parsedline.setExpFactor(1);
    }

    private static void PUSH_Parse(Vector vector, ParsedLine parsedline)
    {
        parsedline.setInst((String)vector.elementAt(1));
        if(vector.size() != 3)
        {
            printError(parsedline, "1 operand required.");
        }
        try
        {
            String s = (String)vector.elementAt(2);
            if(validRegister(s))
            {
                parsedline.setAddrMode(3);
                parsedline.setOperand(0, s);
                parsedline.setExpFactor(2);
            } else
            {
                printError(parsedline, "Operand must be aregister [R0-R15].");
            }
        }
        catch(ArrayIndexOutOfBoundsException arrayindexoutofboundsexception) { }
    }

    private static void NOP_Parse(Vector vector, ParsedLine parsedline)
    {
        parsedline.setInst((String)vector.elementAt(1));
        if(vector.size() != 2)
        {
            printError(parsedline, "No operands permitted.");
        }
        parsedline.setAddrMode(1);
        parsedline.setExpFactor(1);
    }

    private static void LOAD_Parse(Vector vector, ParsedLine parsedline)
    {
        String s = (String)vector.elementAt(1);
        parsedline.setInst(s);
        if(vector.size() < 4)
        {
            printError(parsedline, "At least two operands required for " + s + " instruction.");
        } else
        {
            String s1 = (String)vector.elementAt(2);
            parsedline.setOperand(0, s1);
            if(!validRegister(s1))
            {
                printError(parsedline, "First operand must be a register [R0-R15] for all " + s + " instructions.");
            } else
            {
                String s2 = (String)vector.elementAt(3);
                parsedline.setOperand(1, s2);
                if(s2.startsWith("#") && s.equals("LOAD"))
                {
                    if(validImmediate(s2))
                    {
                        parsedline.setAddrMode(1);
                        if(ParsedLine.getNumValue(s2.substring(1, s2.length())) > (long)MAX_OFFSET || ParsedLine.getNumValue(s2.substring(1, s2.length())) < (long)MIN_OFFSET)
                        {
                            parsedline.setExpFactor(2);
                        } else
                        {
                            parsedline.setExpFactor(1);
                        }
                    } else
                    {
                        parsedline.setAddrMode(2);
                        parsedline.setExpFactor(2);
                        if(!validLabel(s2.substring(1, s2.length())))
                        {
                            printError(parsedline, "Label expected following # in LOAD R #L.");
                        }
                    }
                } else
                if(validLabel(s2))
                {
                    if(vector.size() != 4)
                    {
                        printError(parsedline, "2 operands expected in " + s + " R L.");
                    }
                    parsedline.setAddrMode(3);
                    parsedline.setExpFactor(3);
                } else
                if(validRegister(s2))
                {
                    if(vector.size() == 4)
                    {
                        parsedline.setAddrMode(4);
                        parsedline.setExpFactor(1);
                    } else
                    {
                        String s3 = (String)vector.elementAt(4);
                        parsedline.setOperand(2, s3);
                        if(validOffset(s3))
                        {
                            parsedline.setAddrMode(5);
                            parsedline.setExpFactor(1);
                        } else
                        {
                            printError(parsedline, "Offset expected after + in " + s + " R R +");
                        }
                    }
                } else
                {
                    printError(parsedline, "Invalid format for " + s + " instruction.");
                }
            }
        }
    }

    private static String reg2Bin(String s)
    {
        int i = (int)ParsedLine.getNumValue(s.substring(1, s.length()));
        return Assembler.binString(i, 4);
    }

    private static String imm2Bin16(String s)
    {
        int i = (int)ParsedLine.getNumValue(s.substring(1, s.length()));
        return Assembler.binString(i, 16);
    }

    private static String imm2Bin32(String s)
    {
        int i = (int)ParsedLine.getNumValue(s.substring(1, s.length()));
        return Assembler.binString(i, 32);
    }

    private static boolean validRegLabel(ParsedLine parsedline, String s, String s1)
    {
        if(!validRegister(s))
        {
            printError(parsedline, "First operand must be a register [R0-R15].");
            return false;
        }
        if(!validLabel(s1))
        {
            printError(parsedline, "Second operand must be a label.");
            return false;
        } else
        {
            return true;
        }
    }

    private static boolean validLabelInd(String s)
    {
        return s.charAt(s.length() - 1) == ')' && validLabel(s.substring(0, s.length() - 1));
    }

    private static boolean validIndLabel(String s)
    {
        return s.charAt(0) == '(' && s.charAt(s.length() - 1) == ')' && validLabel(s.substring(1, s.length() - 1));
    }

    private static boolean validIndReg(String s)
    {
        return s.charAt(0) == '(' && validRegister(s.substring(1, s.length()));
    }

    private static boolean validLabel(String s)
    {
        return !validRegister(s) && Character.isLetter(s.charAt(0));
    }

    private static boolean validOffset(String s)
    {
        try
        {
            if(s.startsWith("+"))
            {
                ParsedLine.getNumValue(s.substring(1, s.length()));
                return true;
            } else
            {
                return false;
            }
        }
        catch(NumberFormatException numberformatexception)
        {
            return false;
        }
    }

    private static boolean validImmediate(String s)
    {
        try
        {
            if(s.startsWith("#"))
            {
                ParsedLine.getNumValue(s.substring(1, s.length()));
                return true;
            } else
            {
                return false;
            }
        }
        catch(NumberFormatException numberformatexception)
        {
            return false;
        }
    }

    private static boolean validRegister(String s)
    {
        try
        {
            return s.startsWith("R") && Integer.parseInt(s.substring(1, s.length())) >= 0 && Integer.parseInt(s.substring(1, s.length())) <= 15;
        }
        catch(NumberFormatException numberformatexception)
        {
            return false;
        }
    }

    public static void printError(ParsedLine parsedline, String s)
    {
        System.out.println("Line " + parsedline.getLineNum() + ": " + s);
        parsedline.setError();
    }

    public static void main(String args[])
    {
        AsmFileReader asmfilereader = new AsmFileReader("test-inst.asm");
        for(Vector vector = asmfilereader.nextLine(); vector != null; vector = asmfilereader.nextLine())
        {
            ParsedLine parsedline = new ParsedLine(vector);
        }

    }

    public static final int ADDR_IMMEDIATE = 1;
    public static final int ADDR_IMMEDIATE_LABEL = 2;
    public static final int ADDR_DIRECT = 3;
    public static final int ADDR_INDIRECT = 4;
    public static final int ADDR_STACK = 5;
    private static final int MAX_IMMEDIATE = (int)Math.pow(2D, 16D) - 1;
    private static final int MAX_OFFSET = (int)Math.pow(2D, 15D) - 1;
    private static final int MIN_OFFSET = -(int)Math.pow(2D, 15D);

}
